#include "evaluator_utils.h"
#include <cmath>
#include <cstdlib>
#include <random>

/* *
 * @brief ：生成指定大小的随机 uint64_t 数组，数组中的每个元素在 [1, 65537)
 * 范围内。
 *
 * @param size： 数组的大小，即生成多少个随机数。
 * @param res： 输出数组，存储生成的随机数。
 */
void EvaluatorUtils::RandomUint64Array(long size, uint64_t *res)
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dist(1, 65537);

#pragma omp parallel for
    for (long i = 0; i < size; i++) {
        res[i] = dist(gen) % 65537;
    }
}

/* *
 * @brief
 * ：将给定数组的元素进行左旋转，并使数组中每个元素相等。旋转的位数通过最大公约数来决定。
 *
 * @param vals： 输入数组，存储需要旋转的元素。
 * @param size： 数组的大小。
 * @param rotSize： 旋转的位数。
 */
void EvaluatorUtils::LeftRotateAndEqual(uint64_t *vals, const long size,
                                        const long rotSize)
{
    if (size == 0) {
        return;
    }
    long remRotSize = rotSize % size;
    if (remRotSize != 0) {
        long divisor = Gcd(remRotSize, size);
        if (divisor == 0) {
            return;
        }
        long steps = size / divisor;
        for (long i = 0; i < divisor; i++) {
            uint64_t tmp = vals[i];
            long idx = i;
            for (long j = 0; j < steps - 1; j++) {
                vals[idx] = vals[(idx + remRotSize) % size];
                idx = (idx + remRotSize) % size;
            }
            vals[idx] = tmp;
        }
    }
}

/* *
 * @brief
 * ：将给定数组的元素进行右旋转，并使数组中每个元素相等。右旋转通过左旋转实现。
 *
 * @param vals： 输入数组，存储需要旋转的元素。
 * @param size： 数组的大小。
 * @param rotSize： 旋转的位数。
 */
void EvaluatorUtils::RightRotateAndEqual(uint64_t *vals, const long size,
                                         const long rotSize)
{
    if (size == 0) {
        return;
    }
    int sizeh = size / 2;
    long remRotSize = rotSize % size;
    long leftRemRotSize = (size - remRotSize) % size;
    LeftRotateAndEqual(vals, size, leftRemRotSize);
}

/* *
 * @brief
 * ：将给定数组的元素进行列旋转
 *
 * @param vals： 输入数组，存储需要旋转的元素。
 * @param size： 数组的大小。
 */
void EvaluatorUtils::RotateColumnAndEqual(uint64_t *vals, const long size)
{
    std::swap_ranges(vals, vals + size / 2, vals + size / 2);
}